package db

import (
	"d-serv-go/server/core/bean"
	"d-serv-go/server/core/consts"
	strutils "d-serv-go/server/core/util/stringutils"
)

type SqlBean struct {
	*bean.Bean
}

func NewSqlBean() *SqlBean {
	return &SqlBean{
		Bean:bean.NewBean(""),
	}
}

func (b *SqlBean) And(field string, value interface{}) *SqlBean {
	return b.And2(field, "=", value)
}

func (b *SqlBean) And2(field, op string, value interface{}) *SqlBean {
	b.getWhere().Append(" and ").Append(field).Append(" ").Append(op).Append(" ?")
	b.addVars(value)
	return b
}

func (b *SqlBean) AndInSub(field, subSql string, subValues ...interface{}) *SqlBean {
	b.AndSub(field, "in", subSql, subValues)
	return b
}

func (b *SqlBean) AndSub(field string, op string, subSql string, subValues []interface{}) *SqlBean {
	b.getWhere().Append(" and ").Append(field).Append(" ").Append(op).Append(" (").Append(subSql).Append(")")
	for _, value := range subValues {
		b.addVars(value)
	}
	return b
}

func (b *SqlBean) AndLike(field, value string) *SqlBean {
	b.getWhere().Append(" and ").Append(field).Append(" like CONCAT(CONCAT('%',?),'%')")
	b.addVars(value)
	return b
}

func (b *SqlBean) AndLikeLT(field, value string) *SqlBean {
	b.getWhere().Append(" and ").Append(field).Append(" like CONCAT('%',?)")
	b.addVars(value)
	return b
}

func (b *SqlBean) AndLikeRT(field, value string) *SqlBean {
	b.getWhere().Append(" and ").Append(field).Append(" like CONCAT(?,'%')")
	b.addVars(value)
	return b
}

func (b *SqlBean) AndIn(field string, values ...interface{}) *SqlBean {
	size := len(values)
	if size > 0 {
		sb := b.preIn(values)
		b.getWhere().Append(" and ").Append(field).Append(" in (").Append(sb.ToString()).Append(")")
	}
	return b
}

func (b *SqlBean) AndNotIn(field string, values ...interface{}) *SqlBean {
	size := len(values)
	if size > 0 {
		sb := b.preIn(values)
		b.getWhere().Append(" and ").Append(field).Append(" not in (").Append(sb.ToString()).Append(")")
	}
	return b
}

func (b *SqlBean) preIn(values ...interface{}) *strutils.StringBuilder {
	sb := strutils.NewStringBuilder()
	for _, value := range values {
		sb.Append("?,")
		b.addVars(value)
	}
	sb.Truncate(sb.Len() - 1)
	return sb
}

func (b *SqlBean) AndLt(field string, value interface{}) *SqlBean {
	return b.And2(field, "<", value)
}

func (b *SqlBean) AndLte(field string, value interface{}) *SqlBean {
	return b.And2(field, "<=", value)
}

func (b *SqlBean) AndGt(field string, value interface{}) *SqlBean {
	return b.And2(field, ">", value)
}

func (b *SqlBean) AndGte(field string, value interface{}) *SqlBean {
	return b.And2(field, ">=", value)
}

func (b *SqlBean) AndNot(field string, value interface{}) *SqlBean {
	return b.And2(field, "<>", value)
}

func (b *SqlBean) AndNull(field string, value interface{}) *SqlBean {
	b.getWhere().Append(" and ").Append(field).Append(" is null")
	return b
}

func (b *SqlBean) AndNotNull(field string, value interface{}) *SqlBean {
	b.getWhere().Append(" and ").Append(field).Append(" is not null")
	return b
}

func (b *SqlBean) Or(field, op string, value interface{}) *SqlBean {
	b.getWhere().Append(" or ").Append(field).Append(" ").Append(op).Append(" ?")
	b.addVars(value)
	return b
}

func (b *SqlBean) OrSub(field string, op string, subSql string, subValues []interface{}) *SqlBean {
	b.getWhere().Append(" or ").Append(field).Append(" ").Append(op).Append(" (").Append(subSql).Append(")")
	for _, value := range subValues {
		b.addVars(value)
	}
	return b
}

func (b *SqlBean) OrLike(field, value string) *SqlBean {
	b.getWhere().Append(" or ").Append(field).Append(" like CONCAT(CONCAT('%',?),'%')")
	b.addVars(value)
	return b
}

func (b *SqlBean) OrLikeLT(field, value string) *SqlBean {
	b.getWhere().Append(" or ").Append(field).Append(" like CONCAT('%',?)")
	b.addVars(value)
	return b
}

func (b *SqlBean) OrLikeRT(field, value string) *SqlBean {
	b.getWhere().Append(" or ").Append(field).Append(" like CONCAT(?,'%')")
	b.addVars(value)
	return b
}

func (b *SqlBean) OrIn(field string, values ...interface{}) *SqlBean {
	size := len(values)
	if size > 0 {
		sb := b.preIn(values)
		b.getWhere().Append(" or ").Append(field).Append(" in (").Append(sb.ToString()).Append(")")
	}
	return b
}

func (b *SqlBean) OrNotIn(field string, values ...interface{}) *SqlBean {
	size := len(values)
	if size > 0 {
		sb := b.preIn(values)
		b.getWhere().Append(" or ").Append(field).Append(" not in (").Append(sb.ToString()).Append(")")
	}
	return b
}

func (b *SqlBean) OrNull(field string, value interface{}) *SqlBean {
	b.getWhere().Append(" or ").Append(field).Append(" is null")
	return b
}

func (b *SqlBean) OrNotNull(field string, value interface{}) *SqlBean {
	b.getWhere().Append(" or ").Append(field).Append(" is not null")
	return b
}

func (b *SqlBean) OrNot(field string, value interface{}) *SqlBean {
	return b.Or(field, "<>", value)
}

func (b *SqlBean) Selects(selects string) *SqlBean {
	b.Set(consts.PARAM_SELECT, selects)
	return b
}

func (b *SqlBean) Tables(tables string) *SqlBean {
	b.Set(consts.PARAM_TABLE, tables)
	return b
}

func (b *SqlBean) Groups(groups string) *SqlBean {
	b.Set(consts.PARAM_GROUP, groups)
	return b
}

func (b *SqlBean) Orders(orders string) *SqlBean {
	b.Set(consts.PARAM_ORDER, orders)
	return b
}

func (b *SqlBean) Asc(field string) *SqlBean {
	var order string
	if b.Contains(consts.PARAM_ORDER) {
		order = b.GetStr(consts.PARAM_ORDER) + "," + field
	} else {
		order = field
	}
	b.Set(consts.PARAM_ORDER, order)
	return b
}

func (b *SqlBean) Desc(field string) *SqlBean {
	var order string
	if b.Contains(consts.PARAM_ORDER) {
		order = b.GetStr(consts.PARAM_ORDER) + "," + field + " desc"
	} else {
		order = field + " desc"
	}
	b.Set(consts.PARAM_ORDER, order)
	return b
}

func (b *SqlBean) Limit(count int) *SqlBean {
	b.Set(consts.PAGE_SHOWNUM, count)
	return b
}

func (b *SqlBean) Page(page int) *SqlBean {
	b.Set(consts.PAGE_NOWPAGE, page)
	return b
}

func (b *SqlBean) AppendWhere(where string, values ...interface{}) *SqlBean {
	b.getWhere().Append(where)
	if len(values) > 0 {
		for _, v := range values {
			b.addVars(v)
		}
	}
	return b
}

func (b *SqlBean) getWhere() *strutils.StringBuilder {
	if b.Contains(consts.PARAM_WHERE) {
		if sb, ok := b.Get(consts.PARAM_WHERE).(*strutils.StringBuilder); ok {
			return sb
		}
	}
	sb := strutils.NewStringBuilder("")
	b.Set(consts.PARAM_WHERE, sb)
	return sb
}

func (b *SqlBean) addVars(value interface{}) []interface{} {
	var vars []interface{}
	if b.Contains(consts.PARAM_PRE_VALUES) {
		vars = b.GetArray(consts.PARAM_PRE_VALUES)
	} else {
		vars = make([]interface{}, 0)

	}
	vars = append(vars, value)
	b.Set(consts.PARAM_PRE_VALUES, vars)
	return vars
}
